"use strict";

let gl = null,program = null;

function createShader(gl, type, source) {
  var shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) {
    return shader;
  }

  console.log(gl.getShaderInfoLog(shader));
  gl.deleteShader(shader);
}

function createProgram(element, vertexShaderSource, fragmentShaderSource) {
    var canvas = document.querySelector(element);
    gl = canvas.getContext("webgl");
    if (!gl) {
      return;
    }

    // Set clear color to black, fully opaque
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    // Clear the color buffer with specified clear color
    gl.clear(gl.COLOR_BUFFER_BIT);

      // create GLSL shaders, upload the GLSL source, compile the shaders
    var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
    var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

    program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    var success = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (success) {
        console.log('created program success!');
    }else{
        console.log(gl.getProgramInfoLog(program));
        gl.deleteProgram(program);
    }

    // Tell WebGL how to convert from clip space to pixels
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

    // Tell it to use our program (pair of shaders)
    gl.useProgram(program);

    var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
    gl.uniform3f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height,1000);

    return {gl,program}
}

function drawPoints(drawType,points,size,count){
  var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
  // Turn on the attribute‘
  gl.enableVertexAttribArray(positionAttributeLocation);

  // Create a buffer and put three 2d clip space points in it
  var positionBuffer = gl.createBuffer();
  // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW);

  var type = gl.FLOAT;   // the data is 32bit floats
  var normalize = false; // don't normalize the data
  var stride = 0;        // 0 = move forward size * sizeof(drawType) each iteration to get the next position
  var offset = 0;        // start at the beginning of the buffer
  gl.vertexAttribPointer(
      positionAttributeLocation, size, type, normalize, stride, offset);

  // draw
  gl.drawArrays(drawType, offset, count);
}

/**
 * 构造透视投影矩阵（列主序）
 * @param {number} fov - 垂直视野角（弧度制，如 Math.PI/4）
 * @param {number} aspect - 宽高比（width / height）
 * @param {number} near - 近裁剪面距离（必须 > 0）
 * @param {number} far - 远裁剪面距离（必须 > near）
 * @returns {Float32Array} 4x4 透视矩阵（列主序）
 */
function createPerspectiveMatrix(fov, aspect, near, far) {
  // 1. 计算垂直方向的缩放因子（基于视野角）
  const f = 1.0 / Math.tan(fov / 2); // 相当于 1/tan(fov/2)
  
  // 2. 计算深度范围倒数（用于非线性深度映射）
  const rangeInv = 1.0 / (near - far);

  // 3. 初始化列主序矩阵（16元素 Float32Array）
  const matrix = new Float32Array(16);

  // 第一列
  matrix[0] = f / aspect; // x 缩放（受宽高比影响）
  matrix[1] = 0;
  matrix[2] = 0;
  matrix[3] = 0;

  // 第二列
  matrix[4] = 0;
  matrix[5] = f;          // y 缩放
  matrix[6] = 0;
  matrix[7] = 0;

  // 第三列（深度处理）
  matrix[8] = 0;
  matrix[9] = 0;
  matrix[10] = (far + near) * rangeInv;  // 非线性深度映射
  matrix[11] = -1;                       // 透视除法关键

  // 第四列
  matrix[12] = 0;
  matrix[13] = 0;
  matrix[14] = 2 * far * near * rangeInv; // 深度平移
  matrix[15] = 0;

  return matrix;
}

export { createProgram, drawPoints,createPerspectiveMatrix }